package com.mall.auth.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.douyin.openapi.client.Client;
import com.douyin.openapi.client.models.OauthUserinfoRequest;
import com.douyin.openapi.client.models.OauthUserinfoResponse;
import com.douyin.openapi.credential.models.Config;
import com.mall.auth.entity.OAuth2User;
import com.mall.auth.entity.OAuth2Provider;
import com.mall.auth.service.OAuth2Service;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
// 使用新的类路径
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * OAuth2.0 服务实现类
 */
@Slf4j
@Service
public class OAuth2ServiceImpl implements OAuth2Service {

    @Value("${oauth2.wechat.client-id:}")
    private String wechatClientId;

    @Value("${oauth2.wechat.client-secret:}")
    private String wechatClientSecret;

    @Value("${oauth2.wechat.redirect-uri:}")
    private String wechatRedirectUri;

    @Value("${oauth2.alipay.client-id:}")
    private String alipayClientId;

    @Value("${oauth2.alipay.client-secret:}")
    private String alipayClientSecret;

    @Value("${oauth2.alipay.redirect-uri:}")
    private String alipayRedirectUri;

    @Value("${oauth2.douyin.client-id:}")
    private String douyinClientId;

    @Value("${oauth2.douyin.client-secret:}")
    private String douyinClientSecret;

    @Value("${oauth2.douyin.redirect-uri:}")
    private String douyinRedirectUri;

    @Value("${oauth2.qq.client-id:}")
    private String qqClientId;

    @Value("${oauth2.qq.client-secret:}")
    private String qqClientSecret;

    @Value("${oauth2.qq.redirect-uri:}")
    private String qqRedirectUri;

    private WxMpService wxMpService;
    private AlipayClient alipayClient;
    private Client douyinClient;

    @PostConstruct
    public void init() {
        // 初始化微信服务
        if (isConfigured(wechatClientId, wechatClientSecret)) {
            WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();
            config.setAppId(wechatClientId);
            config.setSecret(wechatClientSecret);
            wxMpService = new WxMpServiceImpl();
            wxMpService.setWxMpConfigStorage(config);
            log.info("微信OAuth2服务初始化成功");
        } else {
            log.warn("微信OAuth2服务配置不完整，跳过初始化");
        }

        // 初始化支付宝服务
        if (isConfigured(alipayClientId, alipayClientSecret)) {
            alipayClient = new DefaultAlipayClient(
                    "https://openapi.alipay.com/gateway.do",
                    alipayClientId,
                    alipayClientSecret,
                    "json",
                    "UTF-8",
                    null,
                    "RSA2"
            );
            log.info("支付宝OAuth2服务初始化成功");
        } else {
            log.warn("支付宝OAuth2服务配置不完整，跳过初始化");
        }
        
        // 初始化抖音服务
        if (isConfigured(douyinClientId, douyinClientSecret)) {
            try {
                Config douyinConfig = new Config();
                douyinConfig.setClientKey(douyinClientId);
                douyinConfig.setClientSecret(douyinClientSecret);
                douyinClient = new Client(douyinConfig);
                log.info("抖音OAuth2服务初始化成功");
            } catch (Exception e) {
                log.error("初始化抖音客户端失败: ", e);
            }
        } else {
            log.warn("抖音OAuth2服务配置不完整，跳过初始化");
        }
    }

    @Override
    public String getAuthorizationUrl(OAuth2Provider provider, String redirectUri) {
        String state = generateState(); // 生成state参数防止CSRF攻击
        
        switch (provider) {
            case WECHAT:
                if (wxMpService == null) {
                    throw new IllegalStateException("微信服务未初始化，请检查配置");
                }
                return wxMpService.getOAuth2Service().buildAuthorizationUrl(redirectUri, "snsapi_login", state);
            case ALIPAY:
                if (alipayClient == null) {
                    throw new IllegalStateException("支付宝服务未初始化，请检查配置");
                }
                return "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=" + alipayClientId +
                        "&scope=auth_user&redirect_uri=" + redirectUri + "&state=" + state;
            case DOUYIN:
                if (douyinClient == null) {
                    throw new IllegalStateException("抖音服务未初始化，请检查配置");
                }
                return "https://open.douyin.com/platform/oauth/connect/?client_key=" + douyinClientId +
                        "&redirect_uri=" + redirectUri + "&scope=user_info&state=" + state + "&response_type=code";
            case QQ:
                if (!isConfigured(qqClientId, qqClientSecret)) {
                    throw new IllegalStateException("QQ服务配置不完整，请检查配置");
                }
                return "https://graph.qq.com/oauth2.0/authorize?client_id=" + qqClientId +
                        "&redirect_uri=" + redirectUri + "&scope=get_user_info&state=" + state + "&response_type=code";
            default:
                throw new IllegalArgumentException("不支持的OAuth2提供商: " + provider);
        }
    }

    @Override
    public String getAccessToken(OAuth2Provider provider, String code, String redirectUri) {
        try {
            switch (provider) {
                case WECHAT:
                    if (wxMpService == null) {
                        throw new IllegalStateException("微信服务未初始化，请检查配置");
                    }
                    WxOAuth2AccessToken wechatToken = wxMpService.getOAuth2Service().getAccessToken(code);
                    return wechatToken.getAccessToken();
                case ALIPAY:
                    if (alipayClient == null) {
                        throw new IllegalStateException("支付宝服务未初始化，请检查配置");
                    }
                    AlipaySystemOauthTokenRequest tokenRequest = new AlipaySystemOauthTokenRequest();
                    tokenRequest.setCode(code);
                    tokenRequest.setGrantType("authorization_code");
                    AlipaySystemOauthTokenResponse tokenResponse = alipayClient.execute(tokenRequest);
                    // 检查响应是否成功
                    if (!tokenResponse.isSuccess()) {
                        throw new RuntimeException("获取支付宝访问令牌失败: " + tokenResponse.getSubMsg());
                    }
                    return tokenResponse.getAccessToken();
                case DOUYIN:
                    if (douyinClient == null) {
                        throw new IllegalStateException("抖音服务未初始化，请检查配置");
                    }
                    // 抖音通过code换取access_token的逻辑
                    String douyinTokenUrl = "https://open.douyin.com/oauth/access_token/?client_key=" + douyinClientId +
                            "&client_secret=" + douyinClientSecret + "&code=" + code + "&grant_type=authorization_code";
                    
                    // 添加重试机制
                    String douyinTokenResponse = executeWithRetry(() -> {
                        RestTemplate restTemplate = new RestTemplate();
                        return restTemplate.getForObject(douyinTokenUrl, String.class);
                    }, 3);
                    
                    JSONObject douyinTokenJson = JSONObject.parseObject(douyinTokenResponse);
                    if (douyinTokenJson.containsKey("data")) {
                        JSONObject data = douyinTokenJson.getJSONObject("data");
                        return data.getString("access_token");
                    }
                    throw new RuntimeException("获取抖音访问令牌失败: " + douyinTokenResponse);
                case QQ:
                    if (!isConfigured(qqClientId, qqClientSecret)) {
                        throw new IllegalStateException("QQ服务配置不完整，请检查配置");
                    }
                    // QQ通过code换取access_token的逻辑
                    String qqTokenUrl = "https://graph.qq.com/oauth2.0/token?client_id=" + qqClientId +
                            "&client_secret=" + qqClientSecret + "&code=" + code + "&grant_type=authorization_code" +
                            "&redirect_uri=" + redirectUri;
                    
                    // 添加重试机制
                    String qqTokenResponse = executeWithRetry(() -> {
                        RestTemplate qqRestTemplate = new RestTemplate();
                        return qqRestTemplate.getForObject(qqTokenUrl, String.class);
                    }, 3);
                    
                    // 解析QQ返回的token格式（类似 access_token=xxx&expires_in=xxx）
                    if (qqTokenResponse != null && qqTokenResponse.contains("access_token=")) {
                        String[] params = qqTokenResponse.split("&");
                        for (String param : params) {
                            if (param.startsWith("access_token=")) {
                                return param.substring("access_token=".length());
                            }
                        }
                    }
                    throw new RuntimeException("获取QQ访问令牌失败: " + qqTokenResponse);
                default:
                    throw new IllegalArgumentException("暂不支持的OAuth2提供商: " + provider);
            }
        } catch (WxErrorException e) {
            log.error("获取微信访问令牌异常: ", e);
            throw new RuntimeException("获取微信访问令牌异常", e);
        } catch (AlipayApiException e) {
            log.error("获取支付宝访问令牌异常: ", e);
            throw new RuntimeException("获取支付宝访问令牌异常", e);
        } catch (Exception e) {
            log.error("获取{}访问令牌异常: ", provider.getName(), e);
            throw new RuntimeException("获取" + provider.getName() + "访问令牌异常", e);
        }
    }

    @Override
    public OAuth2User refreshAccessToken(OAuth2Provider provider, String refreshToken) {
        try {
            switch (provider) {
                case WECHAT:
                    if (wxMpService == null) {
                        throw new IllegalStateException("微信服务未初始化，请检查配置");
                    }
                    // 微信刷新access_token
                    WxOAuth2AccessToken refreshedToken = wxMpService.getOAuth2Service().refreshAccessToken(refreshToken);
                    
                    // 获取用户信息
                    WxOAuth2UserInfo wechatUser = wxMpService.getOAuth2Service().getUserInfo(refreshedToken, null);
                    
                    OAuth2User oAuth2User = new OAuth2User();
                    oAuth2User.setProvider(provider.getCode());
                    oAuth2User.setProviderId(wechatUser.getOpenid());
                    oAuth2User.setNickname(wechatUser.getNickname());
                    oAuth2User.setAvatar(wechatUser.getHeadImgUrl());
                    oAuth2User.setGender(String.valueOf(wechatUser.getSex()));
                    oAuth2User.setAccessToken(refreshedToken.getAccessToken());
                    oAuth2User.setRefreshToken(refreshedToken.getRefreshToken());
                    return oAuth2User;
                    
                case QQ:
                    if (!isConfigured(qqClientId, qqClientSecret)) {
                        throw new IllegalStateException("QQ服务配置不完整，请检查配置");
                    }
                    // QQ刷新access_token
                    String qqRefreshUrl = "https://graph.qq.com/oauth2.0/token?client_id=" + qqClientId +
                            "&client_secret=" + qqClientSecret + "&refresh_token=" + refreshToken + "&grant_type=refresh_token";
                    
                    String qqRefreshResponse = executeWithRetry(() -> {
                        RestTemplate restTemplate = new RestTemplate();
                        return restTemplate.getForObject(qqRefreshUrl, String.class);
                    }, 3);
                    
                    if (qqRefreshResponse != null && qqRefreshResponse.contains("access_token=")) {
                        String[] params = qqRefreshResponse.split("&");
                        String newAccessToken = null;
                        String newRefreshToken = null;
                        
                        for (String param : params) {
                            if (param.startsWith("access_token=")) {
                                newAccessToken = param.substring("access_token=".length());
                            } else if (param.startsWith("refresh_token=")) {
                                newRefreshToken = param.substring("refresh_token=".length());
                            }
                        }
                        
                        // 获取用户OpenId
                        String meUrl = "https://graph.qq.com/oauth2.0/me?access_token=" + newAccessToken;
                        String meResponse = executeWithRetry(() -> {
                            RestTemplate restTemplate = new RestTemplate();
                            return restTemplate.getForObject(meUrl, String.class);
                        }, 3);
                        
                        if (meResponse != null) {
                            int start = meResponse.indexOf("{");
                            int end = meResponse.lastIndexOf("}");
                            if (start != -1 && end != -1 && end > start) {
                                String jsonStr = meResponse.substring(start, end + 1);
                                JSONObject meJson = JSONObject.parseObject(jsonStr);
                                String qqOpenId = meJson.getString("openid");
                                
                                // 获取QQ用户信息
                                String userInfoUrl = "https://graph.qq.com/user/get_user_info?access_token=" + newAccessToken +
                                        "&oauth_consumer_key=" + qqClientId + "&openid=" + qqOpenId;
                                String qqUserInfoResponse = executeWithRetry(() -> {
                                    RestTemplate restTemplate = new RestTemplate();
                                    return restTemplate.getForObject(userInfoUrl, String.class);
                                }, 3);
                                
                                JSONObject userInfoJson = JSONObject.parseObject(qqUserInfoResponse);
                                if ("0".equals(userInfoJson.getString("ret"))) {
                                    OAuth2User qqUser = new OAuth2User();
                                    qqUser.setProvider(provider.getCode());
                                    qqUser.setProviderId(qqOpenId);
                                    qqUser.setNickname(userInfoJson.getString("nickname"));
                                    qqUser.setAvatar(userInfoJson.getString("figureurl_qq_1"));
                                    qqUser.setGender(userInfoJson.getString("gender"));
                                    qqUser.setAccessToken(newAccessToken);
                                    qqUser.setRefreshToken(newRefreshToken);
                                    return qqUser;
                                }
                            }
                        }
                    }
                    throw new RuntimeException("刷新QQ访问令牌失败: " + qqRefreshResponse);
                    
                case DOUYIN:
                case ALIPAY:
                default:
                    throw new UnsupportedOperationException("暂不支持" + provider.getName() + "的Token刷新功能");
            }
        } catch (Exception e) {
            log.error("刷新{}访问令牌异常: ", provider.getName(), e);
            throw new RuntimeException("刷新" + provider.getName() + "访问令牌异常", e);
        }
    }

    @Override
    public OAuth2User getUserInfo(OAuth2Provider provider, String accessToken) {
        try {
            switch (provider) {
                case WECHAT:
                    if (wxMpService == null) {
                        throw new IllegalStateException("微信服务未初始化，请检查配置");
                    }
                    WxOAuth2AccessToken token = new WxOAuth2AccessToken();
                    token.setAccessToken(accessToken);
                    // 使用正确的返回类型
                    WxOAuth2UserInfo wechatUser = wxMpService.getOAuth2Service().getUserInfo(token, null);
                    OAuth2User oAuth2User = new OAuth2User();
                    oAuth2User.setProvider(provider.getCode());
                    oAuth2User.setProviderId(wechatUser.getOpenid());
                    oAuth2User.setNickname(wechatUser.getNickname());
                    oAuth2User.setAvatar(wechatUser.getHeadImgUrl());
                    // 将Integer类型转换为String类型
                    oAuth2User.setGender(String.valueOf(wechatUser.getSex()));
                    oAuth2User.setAccessToken(accessToken);
                    return oAuth2User;
                case ALIPAY:
                    if (alipayClient == null) {
                        throw new IllegalStateException("支付宝服务未初始化，请检查配置");
                    }
                    AlipayUserInfoShareRequest userInfoRequest = new AlipayUserInfoShareRequest();
                    AlipayUserInfoShareResponse userInfoResponse = alipayClient.execute(userInfoRequest, accessToken);
                    // 检查响应是否成功
                    if (!userInfoResponse.isSuccess()) {
                        throw new RuntimeException("获取支付宝用户信息失败: " + userInfoResponse.getSubMsg());
                    }
                    OAuth2User alipayUser = new OAuth2User();
                    alipayUser.setProvider(provider.getCode());
                    alipayUser.setProviderId(userInfoResponse.getUserId());
                    alipayUser.setNickname(userInfoResponse.getNickName());
                    alipayUser.setAvatar(userInfoResponse.getAvatar());
                    alipayUser.setGender(userInfoResponse.getGender());
                    alipayUser.setAccessToken(accessToken);
                    return alipayUser;
                case DOUYIN:
                    if (douyinClient == null) {
                        throw new IllegalStateException("抖音服务未初始化，请检查配置");
                    }
                    // 抖音获取用户OpenId
                    String openIdUrl = "https://open.douyin.com/oauth/userinfo/?access_token=" + accessToken;
                    
                    String openIdResponse = executeWithRetry(() -> {
                        RestTemplate restTemplate = new RestTemplate();
                        return restTemplate.getForObject(openIdUrl, String.class);
                    }, 3);
                    
                    JSONObject openIdJson = JSONObject.parseObject(openIdResponse);
                    if (!openIdJson.containsKey("data")) {
                        throw new RuntimeException("获取抖音用户OpenId失败: " + openIdResponse);
                    }
                    JSONObject openIdData = openIdJson.getJSONObject("data");
                    String openId = openIdData.getString("open_id");
                    
                    // 抖音获取用户信息
                    OauthUserinfoRequest douyinUserInfoRequest = new OauthUserinfoRequest();
                    douyinUserInfoRequest.setAccessToken(accessToken);
                    douyinUserInfoRequest.setOpenId(openId);
                    OauthUserinfoResponse douyinUserInfoResponse = douyinClient.OauthUserinfo(douyinUserInfoRequest);
                    
                    OAuth2User douyinUser = new OAuth2User();
                    douyinUser.setProvider(provider.getCode());
                    douyinUser.setProviderId(openId);
                    douyinUser.setNickname(douyinUserInfoResponse.getData().getNickname());
                    douyinUser.setAvatar(douyinUserInfoResponse.getData().getAvatar());
                    // 抖音API返回的性别是字符串类型，不需要转换，如果没有性别字段则设为空字符串
                    String gender = "";
                    // 由于无法确定OauthUserinfoResponseData的具体方法，我们通过反射方式获取性别信息
                    try {
                        // 尝试通过反射获取性别字段
                        java.lang.reflect.Method genderMethod = douyinUserInfoResponse.getData().getClass().getMethod("getGender");
                        Object genderObj = genderMethod.invoke(douyinUserInfoResponse.getData());
                        if (genderObj != null) {
                            gender = genderObj.toString();
                        }
                    } catch (Exception e) {
                        log.warn("通过反射获取抖音用户性别信息失败: {}", e.getMessage());
                    }
                    douyinUser.setGender(gender);
                    douyinUser.setAccessToken(accessToken);
                    return douyinUser;
                case QQ:
                    if (!isConfigured(qqClientId, qqClientSecret)) {
                        throw new IllegalStateException("QQ服务配置不完整，请检查配置");
                    }
                    // 获取QQ用户OpenId
                    String meUrl = "https://graph.qq.com/oauth2.0/me?access_token=" + accessToken;
                    
                    String meResponse = executeWithRetry(() -> {
                        RestTemplate qqRestTemplate = new RestTemplate();
                        return qqRestTemplate.getForObject(meUrl, String.class);
                    }, 3);
                    
                    // 解析回调函数格式：callback( {"client_id":"xxx","openid":"xxx"} );
                    if (meResponse != null) {
                        int start = meResponse.indexOf("{");
                        int end = meResponse.lastIndexOf("}");
                        if (start != -1 && end != -1 && end > start) {
                            String jsonStr = meResponse.substring(start, end + 1);
                            JSONObject meJson = JSONObject.parseObject(jsonStr);
                            String qqOpenId = meJson.getString("openid");
                            
                            // 获取QQ用户信息
                            String userInfoUrl = "https://graph.qq.com/user/get_user_info?access_token=" + accessToken +
                                    "&oauth_consumer_key=" + qqClientId + "&openid=" + qqOpenId;
                            
                            String qqUserInfoResponse = executeWithRetry(() -> {
                                RestTemplate qqRestTemplate = new RestTemplate();
                                return qqRestTemplate.getForObject(userInfoUrl, String.class);
                            }, 3);
                            
                            JSONObject userInfoJson = JSONObject.parseObject(qqUserInfoResponse);
                            
                            if (!"0".equals(userInfoJson.getString("ret"))) {
                                throw new RuntimeException("获取QQ用户信息失败: " + qqUserInfoResponse);
                            }
                            
                            OAuth2User qqUser = new OAuth2User();
                            qqUser.setProvider(provider.getCode());
                            qqUser.setProviderId(qqOpenId);
                            qqUser.setNickname(userInfoJson.getString("nickname"));
                            qqUser.setAvatar(userInfoJson.getString("figureurl_qq_1"));
                            qqUser.setGender(userInfoJson.getString("gender"));
                            qqUser.setAccessToken(accessToken);
                            return qqUser;
                        }
                    }
                    throw new RuntimeException("获取QQ用户OpenId失败: " + meResponse);
                default:
                    throw new IllegalArgumentException("暂不支持的OAuth2提供商: " + provider);
            }
        } catch (WxErrorException e) {
            log.error("获取微信用户信息异常: ", e);
            throw new RuntimeException("获取微信用户信息异常", e);
        } catch (AlipayApiException e) {
            log.error("获取支付宝用户信息异常: ", e);
            throw new RuntimeException("获取支付宝用户信息异常", e);
        } catch (Exception e) {
            log.error("获取{}用户信息异常: ", provider.getName(), e);
            throw new RuntimeException("获取" + provider.getName() + "用户信息异常", e);
        }
    }

    @Override
    public String generateQRCodeContent(OAuth2Provider provider, String state) {
        String redirectUri = getRedirectUri(provider);
        switch (provider) {
            case WECHAT:
                if (wxMpService == null) {
                    throw new IllegalStateException("微信服务未初始化，请检查配置");
                }
                return "https://open.weixin.qq.com/connect/qrconnect?appid=" + wechatClientId +
                        "&redirect_uri=" + redirectUri + "&response_type=code&scope=snsapi_login&state=" + state + "#wechat_redirect";
            case ALIPAY:
                if (alipayClient == null) {
                    throw new IllegalStateException("支付宝服务未初始化，请检查配置");
                }
                return "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=" + alipayClientId +
                        "&scope=auth_user&redirect_uri=" + redirectUri + "&state=" + state;
            case DOUYIN:
                if (douyinClient == null) {
                    throw new IllegalStateException("抖音服务未初始化，请检查配置");
                }
                return "https://open.douyin.com/platform/oauth/connect/?client_key=" + douyinClientId +
                        "&redirect_uri=" + redirectUri + "&scope=user_info&state=" + state + "&response_type=code";
            case QQ:
                if (!isConfigured(qqClientId, qqClientSecret)) {
                    throw new IllegalStateException("QQ服务配置不完整，请检查配置");
                }
                return "https://graph.qq.com/oauth2.0/authorize?client_id=" + qqClientId +
                        "&redirect_uri=" + redirectUri + "&scope=get_user_info&state=" + state + "&response_type=code";
            default:
                throw new IllegalArgumentException("不支持的OAuth2提供商: " + provider);
        }
    }

    /**
     * 生成state参数，用于防止CSRF攻击
     * 
     * @return 随机生成的state字符串
     */
    private String generateState() {
        return UUID.randomUUID().toString();
    }

    /**
     * 检查配置是否完整
     * 
     * @param clientId 客户端ID
     * @param clientSecret 客户端密钥
     * @return 是否配置完整
     */
    private boolean isConfigured(String clientId, String clientSecret) {
        return clientId != null && !clientId.isEmpty() && 
               clientSecret != null && !clientSecret.isEmpty();
    }

    private String getRedirectUri(OAuth2Provider provider) {
        switch (provider) {
            case WECHAT:
                return wechatRedirectUri;
            case ALIPAY:
                return alipayRedirectUri;
            case DOUYIN:
                return douyinRedirectUri;
            case QQ:
                return qqRedirectUri;
            default:
                throw new IllegalArgumentException("不支持的OAuth2提供商: " + provider);
        }
    }
    
    /**
     * 带重试机制的网络请求执行方法
     * 
     * @param requestFunc 网络请求函数
     * @param maxRetries 最大重试次数
     * @return 请求结果
     */
    private <T> T executeWithRetry(RequestFunction<T> requestFunc, int maxRetries) {
        Exception lastException = null;
        
        for (int i = 0; i <= maxRetries; i++) {
            try {
                return requestFunc.execute();
            } catch (Exception e) {
                lastException = e;
                log.warn("网络请求失败，正在进行第{}次重试: {}", i + 1, e.getMessage());
                
                if (i < maxRetries) {
                    // 指数退避策略，最多等待5秒
                    try {
                        long delay = Math.min((long) Math.pow(2, i) * 1000, 5000);
                        TimeUnit.MILLISECONDS.sleep(delay);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("重试过程中被中断", ie);
                    }
                }
            }
        }
        
        throw new RuntimeException("网络请求重试" + (maxRetries + 1) + "次后仍然失败", lastException);
    }
    
    /**
     * 网络请求函数接口
     * 
     * @param <T> 返回值类型
     */
    @FunctionalInterface
    private interface RequestFunction<T> {
        T execute() throws Exception;
    }
}